package com.example.mysql.学习笔记.基础.约束;

public class 外键约束 {
}
/**
 * **FOREIGN KEY**  **外键约束**
 * 限定某个表的某个字段的引用完整性。
 * 比如：员工表的员工所在部门的选择，必须在部门表能找到对应的部分。
 *
 * 主表和从表/父表和子表          可以同一个表的不同字段  进行外键关联
 *
 * 主表（父表）：被引用的表，被参考的表
 * 从表（子表）：引用别人的表，参考别人的表
 *
 * 例如：员工表的员工所在部门这个字段的值要参考部门表：部门表是主表，员工表是从表。
 * 例如：学生表、课程表、选课表：选课表的学生和课程要分别参考学生表和课程表，
 *      学生表和课程表是主表，选课表是从表。
 *
 *  特点
 *
 * （1）从表的外键列，必须引用/参考主表的主键或唯一约束的列
 *    为什么？     因为被依赖/被参考的值必须是唯一的
 * （2）在创建外键约束时，如果不给外键约束命名，**默认名不是列名，而是自动产生一个外键名**
 *      （例如 student_ifblk_1;），也可以指定外键约束名。
 * （3）创建(CREATE)表时就指定外键约束的话，"先创建主表，再创建从表"
 * （4）删表时，先删从表（或先删除外键约束），再删除主表
 * （5）当主表的记录被从表参照时，主表的记录将不允许删除，
 *      如果要删除数据，需要先删除从表中依赖该记录的数据，然后才可以删除主表的数据
 * （6）在“从表”中指定外键约束，并且一个表可以建立多个外键约束
 * （7）从表的外键列与 主表被参照的列 "名字可以不相同"，但是
 *      数据类型必须一样，逻辑意义一致。
 *      如果类型不一样，创建子表时，就会出现错误“ERROR 1005 (HY000):Can't create table'database.tablename'(errno: 150)”。
 *      例如：都是表示部门编号，都是int类型。
 * （8）**当创建外键约束时，系统默认会在所在的列上建立对应的普通索引**。
 *      但是索引名是外键的约束名。（根据外键查询效率很高）
 * （9）删除外键约束后，必须`手动`删除对应的索引
 */

/**
 * 添加外键约束
 * -- FOREIGN KEY: 在表级指定子表中的列
 * -- REFERENCES: 标示在父表中的列
 * CREATE TABLE IF NOT EXISTS 表名(
 * 字段名 数据类型 约束,
 * 字段名 数据类型,
 *
 * //表级约束   CONSTRAINT 约束名字   可不要
 * CONSTRAINT 约束名字 FOREIGN KEY(本表字段) REFERENCES 父表(父表中的列)
 * );
 *
 * ALTER TABLE 表名称
 * ADD
 * CONSTRAINT 约束名字 FOREIGN KEY(本表字段) REFERENCES 父表(父表中的列)
 *
 */

/**
 * 添加外键数据时 外键的值   在主键必须存在
 * 删除主键数据   外键必须不存在此主键的信息
 *
 * (1)第一步先查看约束名和删除外键约束
 * SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';#查看某个表的约束名
 *      ALTER TABLE 从表名
 *      DROP FOREIGN KEY 外键约束名;
 *
 * （2）第二步查看索引名和删除索引。（注意，只能手动删除）
 * SHOW INDEX FROM 表名称; #查看某个表的索引名
 *
 * ALTER TABLE 从表名 DROP INDEX 索引名;
 */

/**
 * 约束等级
 *
 * * `Cascade方式`：在父表上update/delete记录时，
 *      同步update/delete掉子表的匹配记录
 * * `Set null方式`：在父表上update/delete记录时，
 *      将子表上匹配记录的列设为null，但是要注意子表的外键列不能为not null
 * * `No action方式`：如果子表中有匹配的记录，则不允许对父表对应候选键进行update/delete操作
 * * `Restrict方式`：同no action， 都是立即检查外键约束
 * * `Set default方式`（在可视化工具SQLyog中可能显示空白）：
 *      父表有变更时，子表将外键列设置成一个默认的值，但Innodb不能识别
 *
 * 如果没有指定等级，就相当于Restrict方式。
 *
 * 对于外键约束，最好是采用: `ON UPDATE CASCADE ON DELETE RESTRICT` 的方式。 //Restrict方式
 * 对于外键约束，最好是采用: `ON UPDATE CASCADE ON DELETE (可变参数))` 的方式。 //Restrict方式
 *
 *
 */

/**
 * 开发场景
 * 问题1：如果两个表之间有关系（一对一、一对多），
 * 比如：员工表和部门表（一对多），它们之间是否一定要建外键约束？
 * 答：不是的
 *
 * **问题2：建和不建外键约束有什么区别？**
 *
 * 答：建外键约束，你的操作（创建表、删除表、添加、修改、删除）会受到限制，从语法层面受到限制。
 * 例如：在员工表中不可能添加一个员工信息，它的部门的值在部门表中找不到。
 * 不建外键约束，你的操作（创建表、删除表、添加、修改、删除）不受限制，要保证数据的`引用完整性`，
 * 只能依`靠程序员的自觉`，或者是`在Java程序中进行限定`。
 * 例如：在员工表中，可以添加一个员工的信息，它的部门指定为一个完全不存在的部门。
 *
 * **问题3：那么建和不建外键约束和查询有没有关系？**
 * 答：没有
 * > 在 MySQL 里，外键约束是有成本的，需要消耗系统资源。
 *   对于大并发的 SQL 操作，有可能会不适合。
 *   比如大型网站的中央数据库，可能会`因为外键约束的系统开销而变得非常慢`。
 *   所以，MySQL 允许你不使用系统自带的外键约束，在`应用层面`完成检查数据一致性的逻辑。
 *   也就是说，即使你不用外键约束，也要想办法通过应用层面的附加逻辑，
 *   来实现外键约束的功能，确保数据的一致性。
 *
 * ### 阿里开发规范
 * 【`强制`】不得使用外键与级联，一切外键概念必须在应用层解决。
 *
 * 说明：（概念解释）学生表中的 student_id 是主键，
 * 那么成绩表中的 student_id 则为外键。
 * 如果更新学生表中的 student_id，同时触发成绩表中的 student_id 更新，即为级联更新。
 * 外键与级联更新适用于`单机低并发`，不适合`分布式`、`高并发集群`；
 * 级联更新是强阻塞，存在数据库`更新风暴`的风险；外键影响数据库的`插入速度`。
 *
 *
 * 总的来说  外键不会增加查询效率  而且还会增加  增删改查  的速度，
 *      所以我们一般都在应用层实现外键的功能
 *
 */
